package com.giscloud.redis.config;

import org.apache.commons.pool2.impl.GenericObjectPoolConfig;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.ClassPathResource;
import org.springframework.data.redis.connection.RedisClusterConfiguration;
import org.springframework.data.redis.connection.RedisNode;
import org.springframework.data.redis.connection.RedisPassword;
import org.springframework.data.redis.connection.RedisStandaloneConfiguration;
import org.springframework.data.redis.connection.lettuce.LettuceClientConfiguration;
import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory;
import org.springframework.data.redis.connection.lettuce.LettucePoolingClientConfiguration;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.script.DefaultRedisScript;
import org.springframework.data.redis.core.script.RedisScript;
import org.springframework.data.redis.serializer.StringRedisSerializer;
import org.springframework.util.StringUtils;

import java.util.HashSet;
import java.util.Set;

/**
 * @Author:gxd
 * @Description:缓存配置-使用Lettuce客户端，自动注入配置的方式
 * @Date: 10:54 2019/7/17
 * @Modified By:
 */
@Configuration
@ConditionalOnExpression("'${spring.redis.type}'!='sentinel'")
public class RedisConfig {
    @Autowired
    private RedisProperties redisProperties;

    @Bean(name="rTemplate")
    public CustomRedisTemplate<String, Object> rTemplate(@Qualifier("lcFactory") LettuceConnectionFactory lcFactory) {
        //创建Redis缓存操作助手RedisTemplate对象,StringRedisTemplate是RedisTempLate<String, String>的子类
        CustomRedisTemplate<String, Object> template = new CustomRedisTemplate();
        template.setConnectionFactory(lcFactory);
        StringRedisSerializer srSerializer = new StringRedisSerializer();
        // key采用String的序列化方式
        template.setKeySerializer(srSerializer);
        // hash的key也采用String的序列化方式
        template.setHashKeySerializer(srSerializer);
        // value序列化方式采用String的序列化方式
        template.setValueSerializer(srSerializer);
        // hash的value序列化方式采用String的序列化方式
        template.setHashValueSerializer(srSerializer);
        // 开启事务
        template.setEnableTransactionSupport(true);
        template.afterPropertiesSet();
        return template;
    }

    @Bean(name="sTemplate")
    public CustomRedisTemplate sTemplate(@Qualifier("lcFactory") LettuceConnectionFactory lcFactory) {
        CustomRedisTemplate<String, String> template = new CustomRedisTemplate();
        template.setConnectionFactory(lcFactory);
        StringRedisSerializer srSerializer = new StringRedisSerializer();
        // key采用String的序列化方式
        template.setKeySerializer(srSerializer);
        // hash的key也采用String的序列化方式
        template.setHashKeySerializer(srSerializer);
        // value序列化方式采用String的序列化方式
        template.setValueSerializer(srSerializer);
        // hash的value序列化方式采用String的序列化方式
        template.setHashValueSerializer(srSerializer);
        // 开启事务
        template.setEnableTransactionSupport(true);
        template.afterPropertiesSet();
        return template;
    }

    @Bean(name="rateLimiterClientLua")
    public RedisScript<Long> rateLimiterClientLua() {
        DefaultRedisScript redisScript = new DefaultRedisScript();
        redisScript.setLocation(new ClassPathResource("rate_limiter.lua"));
        redisScript.setResultType(Long.class);
        return redisScript;
    }
    /**
     * GenericObjectPoolConfig 连接池配置
     *
     * @return
     */
    @Bean(name = "poolConfig")
    public GenericObjectPoolConfig genericObjectPoolConfig() {
        GenericObjectPoolConfig genericObjectPoolConfig = new GenericObjectPoolConfig();
        genericObjectPoolConfig.setMaxIdle(redisProperties.getLettuce().getPool().getMaxIdle());
        genericObjectPoolConfig.setMinIdle(redisProperties.getLettuce().getPool().getMinIdle());
        genericObjectPoolConfig.setMaxTotal(redisProperties.getLettuce().getPool().getMaxActive());
        genericObjectPoolConfig.setMaxWaitMillis(redisProperties.getLettuce().getPool().getMaxWait().toMillis());
        return genericObjectPoolConfig;
    }


    @Bean(name="lcFactory")
    LettuceConnectionFactory lettuceConnectionFactory(@Qualifier("poolConfig") GenericObjectPoolConfig poolConfig) {
        LettuceConnectionFactory factory = null;
        LettuceClientConfiguration lettuceClientConfiguration = LettucePoolingClientConfiguration.builder()
                .commandTimeout(redisProperties.getTimeout())
                .poolConfig(poolConfig)
                .build();
        if ("cluster".equals(redisProperties.getType())) {
            // 集群版配置
            RedisClusterConfiguration redisClusterConfiguration = new RedisClusterConfiguration();
            Set<RedisNode> nodes = new HashSet<>();
            for (String ipPort : redisProperties.getCluster().getNodes()) {
                String[] ipAndPort = ipPort.split(":");
                nodes.add(new RedisNode(ipAndPort[0].trim(), Integer.valueOf(ipAndPort[1])));
            }
            if (!StringUtils.isEmpty(redisProperties.getPassword())) {
                redisClusterConfiguration.setPassword(RedisPassword.of(redisProperties.getPassword()));
            }
            redisClusterConfiguration.setClusterNodes(nodes);
            redisClusterConfiguration.setMaxRedirects(redisProperties.getCluster().getMaxRedirects());
            factory = new LettuceConnectionFactory(redisClusterConfiguration, lettuceClientConfiguration);
        } else if ("standalone".equals(redisProperties.getType())) {
            // 单机版配置
            RedisStandaloneConfiguration redisStandaloneConfiguration = new RedisStandaloneConfiguration();
            redisStandaloneConfiguration.setDatabase(redisProperties.getDatabase());
            redisStandaloneConfiguration.setHostName(redisProperties.getHost());
            redisStandaloneConfiguration.setPort(redisProperties.getPort());
            if (!StringUtils.isEmpty(redisProperties.getPassword())) {
                redisStandaloneConfiguration.setPassword(RedisPassword.of(redisProperties.getPassword().toCharArray()));
            }
            factory = new LettuceConnectionFactory(redisStandaloneConfiguration, lettuceClientConfiguration);
        }
        return factory;
    }

}

